💡 AI 인사이트

🤖 AI가 여기에 결과를 출력합니다...

댓글 커뮤니티

쿠팡이벤트

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

검색

    로딩 중이에요... 🐣

    [코담] 웹개발·실전 프로젝트·AI까지, 파이썬·장고의 모든것을 담아낸 강의와 개발 노트

    20 템플릿, 미들웨어 | ✅ 저자: 이유정(박사)

    Jinja(진자)는 파이썬에서 사용하는 HTML 템플릿 엔진입니다.

    • HTML 안에 {% ... %}, {{ ... }} 같은 파이썬 코드나 변수를 넣어서 웹페이지를 자동으로 만들어주는 도구예요.
    • 예: 장고(Django), 플라스크(Flask), FastAPI에서 HTML을 자동 생성할 때 사용됩니다. 쉽게 설명하면 Jinja = HTML 코드 속에 파이썬 변수를 껴 넣어서 웹페이지를 만들어주는 도구입니다.
    Jinja2는 Django 템플릿과 거의 똑같은 역할을 하는 템플릿 엔진입니다.
    항목 Jinja2 (FastAPI, Flask 등) Django 템플릿
    사용 목적 HTML + 변수/제어문 섞어서 웹페이지 생성 동일
    문법 {{ 변수 }}, {% for %}, {% if %} 거의 동일
    장점 가볍고 빠름, 다양한 프레임워크에 사용됨 Django에 최적화됨
    내장 함수 range(), len(), default() 등 다양 비슷하지만 Django는 자체 필터 많음
    사용자 정의 필터 @app.template_filter 등으로 직접 추가 가능 Django도 custom filter 가능

    일반 HTML

    <h1>안녕하세요!</h1>
    

    이건 항상 "안녕하세요!"만 출력돼요. 사용자 이름을 바꿀 수 없죠.

    Jinja 템플릿 (파이썬 변수 삽입)

    <h1>안녕하세요, {{ username }}님!</h1>
    

    그리고 Python에서 이렇게 보내줍니다.

    from fastapi import FastAPI, Request
    from fastapi.templating import Jinja2Templates
    
    app = FastAPI()
    templates = Jinja2Templates(directory="templates")
    
    @app.get("/hello")
    def say_hello(request: Request):
        return templates.TemplateResponse("hello.html", {
            "request": request,
            "username": "Eunice"
        })
    

    이 코드를 실행하면 "안녕하세요, Eunice님!"** 이라고 실제로 HTML이 바뀌어 렌더링돼요.

    Jinja2설치

    pip install jinja2
    

    폴더구조

    jinja_app/
    │
    ├── main.py
    └── templates/
        ├── hello.html
        └── users.html
    

    main.py

    from fastapi import FastAPI, Request
    from fastapi.responses import HTMLResponse
    from fastapi.templating import Jinja2Templates
    
    app = FastAPI()
    
    # 템플릿 디렉토리 설정
    templates = Jinja2Templates(directory="templates")
    
    # 기본 인사 페이지
    @app.get("/", response_class=HTMLResponse)
    def read_root(request: Request):
        return templates.TemplateResponse("hello.html", {
            "request": request,
            "username": "유정이"
        })
    
    # 사용자 리스트 페이지
    @app.get("/users", response_class=HTMLResponse)
    def show_users(request: Request):
        user_list = ["Alice", "Bob", "Charlie", "David"]
        return templates.TemplateResponse("users.html", {
            "request": request,
            "users": user_list
        })
    

    templates/hello.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>Hello</title>
    </head>
    <body>
        <h1><a href=/users>안녕하세요, {{ username }}님!</a></h1>
    </body>
    </html>
    

    fast api에서 링크이동은 라우트 경로로 이동합니다.

    templates/users.html

    <!DOCTYPE html>
    <html>
    <head>
        <title>사용자 목록</title>
    </head>
    <body>
        <h2>사용자 리스트</h2>
        <ul>
            {% for user in users %}
                <li>{{ user }}</li>
            {% endfor %}
        </ul>
    </body>
    </html>
    

    실행 프로젝트 폴더로 이동

    cd jinja_app
    

    필요한 패키지 설치 uvicorn[standard]

    pip install fastapi jinja2 "uvicorn[standard]"
    

    FastAPI는 자체 웹서버가 없기 때문에, 서버 실행을 위해 uvicorn이라는 ASGI 서버가 필요합니다.

    서버 실행

    uvicorn main:app --reload
    
    1. 브라우저로 접속

    fast api하드코딩 방식보다 Jinja2의 url_for 사용을 권장합니다:

    <a href="{{ url_for('show_users') }}">안녕하세요, {{ username }}님!</a>
    

    단, 이 경우에는 show_users() 함수에 이름을 붙여야 합니다:

    @app.get("/users", response_class=HTMLResponse, name="show_users")
    def show_users(request: Request):
    

    미들웨어(Middleware)란? 미들웨어는 “중간에서 도와주는 프로그램”이에요.
    쉽게 말해서, 두 프로그램 사이에서 '다리' 역할을 하는 도우미입니다. 미들웨어는 운영체제(OS)가 제공하는 기본 기능 외에,
    애플리케이션들이 서로 소통하고 동작할 수 있게 해주는 추가 소프트웨어입니다.

    미들웨어가 하는 일 예시:
    기능 예시
    보안 요청에 인증 정보가 있는지 확인
    로깅 누가 언제 어떤 요청을 보냈는지 기록
    오류 처리 에러가 나면 예쁘게 알려주기
    CORS 다른 출처에서 온 요청을 허용할지 판단
    데이터 압축 응답 데이터를 gzip으로 압축해서 보내기
    Django, FastAPI, Express.js 등에서는 요청(Request)이 들어오고 → 응답(Response)을 보내기 전에 중간에서 무언가를 처리하는 코드를 미들웨어라고 부릅니다.

    요청이 처리되기까지 걸린 시간(초)을 응답 헤더에 X-Process-Time이라는 이름으로 붙여서 반환하는 예시코드:

    import time
    from fastapi import FastAPI, Request
    from fastapi.responses import JSONResponse
    
    app = FastAPI()
    
    # 미들웨어 구현
    @app.middleware("http")
    async def add_process_time_header(request: Request, call_next):
        start_time = time.time()  # 요청 시작 시간 기록
        response = await call_next(request)  # 실제 요청 처리
        process_time = time.time() - start_time  # 처리 시간 계산
        response.headers["X-Process-Time"] = str(process_time)  # 응답 헤더에 추가
        return response
    
    # 테스트용 엔드포인트
    @app.get("/ping")
    async def ping():
        return {"message": "pong"}
    

    실행해보기

    uvicorn main:app --reload
    

    결과 확인 방법: 브라우저에서 http://localhost:8000/ping 접속 F12 → Network 탭 → ping 요청 클릭 "Headers" 탭 → Response Headers에서 아래 항목 확인:

    X-Process-Time: 0.0003476142883300781
    

    이게 바로 미들웨어가 처리한 요청 처리 시간이에요.

    터미널에서

    curl -i http://localhost:8000/ping
    

    결과:

    HTTP/1.1 200 OK
    X-Process-Time: 0.00045
    content-type: application/json
    ...
    {"message":"pong"}
    

    X-Process-Time 헤더가 응답에 붙어 있으면 미들웨어가 잘 작동한 것입니다!

    실제 FastAPI 프로젝트구조에서 미들웨어 코드 위치:

    myproject/
    ├── app/
    │   ├── __init__.py
    │   ├── main.py              ← FastAPI 인스턴스(app) 생성 위치
    │   ├── middleware/          ← ✅ 미들웨어 모듈 저장
    │   │   ├── __init__.py
    │   │   └── process_time.py  ← 지금 만든 미들웨어
    │   ├── routes/
    │   │   └── ping.py          ← /ping 같은 라우트들
    │   └── ...
    ├── requirements.txt
    └── run.py                   ← uvicorn 실행 진입점
    

    미들웨어 코드 분리 예시 (process_time.py)

    # app/middleware/process_time.py
    
    import time
    from fastapi import Request
    
    async def add_process_time_header(request: Request, call_next):
        start_time = time.time() # 요청 시작 시각 기록
        response = await call_next(request) # 실제 라우터 핸들러 호출
        process_time = time.time() - start_time # 처리 시간 계산
        response.headers["X-Process-Time"] = str(process_time)
        # 응답 헤더에 삽입
        
        return response
    

    목적: 요청이 들어온 시점부터 응답을 마치기까지 걸린 시간을 계산해서,
    응답 헤더에 X-Process-Time이라는 커스텀 정보를 추가하는 것이 목적입니다.

    목적 예시
    요청 시간 측정 API 응답 지연 여부 모니터링
    요청 로깅 누가 어떤 URL에 요청을 했는지 로그 파일에 저장
    인증 검사 Authorization 헤더 유효성 확인 후 401 반환
    응답 가공 특정 응답에 공통 헤더 삽입 (예: CORS, 보안 헤더 등)
    사용자 IP 추적 request.client.host로 사용자 IP 기록

    FastAPI 인스턴스(app)에 미들웨어 등록 (main.py)

    # app/main.py
    
    from fastapi import FastAPI
    from app.middleware.process_time import add_process_time_header
    
    app = FastAPI()
    
    # 미들웨어 등록
    app.middleware("http")(add_process_time_header)
    
    # 라우터 등록 예시
    from app.routes import ping
    app.include_router(ping.router)
    

    라우터 예시 (routes/ping.py)

    # app/routes/ping.py
    
    from fastapi import APIRouter
    
    router = APIRouter()
    
    @router.get("/")
    async def root():
        return {"message": "Welcome to the API"}
    
    @router.get("/ping")
    async def ping():
        return {"message": "pong"}
    

    main.py에 있던 기능을 routes/ping.py로 분리해서 라우터로 등록한 것

    일반적인 fastAPI 라우터 구조예시

    app/
    ├── main.py                     ← 앱 생성 및 라우터 등록
    ├── routes/
    │   ├── auth.py                ← 로그인, 회원가입, 인증
    │   ├── users.py               ← 회원정보, 유저조회
    │   ├── posts.py               ← 글쓰기, 조회, 삭제
    │   ├── comments.py            ← 댓글 작성/삭제
    │   ├── ping.py                ← 서버 상태 점검
    │   └── __init__.py
    

    실행 진입점 (run.py)

    # run.py
    import uvicorn
    
    if __name__ == "__main__":
        uvicorn.run("main:app", reload=True)
    

    서버실행

    python run.py
    

    결과:

    위 결과의 전체 요약

    • 요청 URL: http://127.0.0.1:8000/ → 브라우저가 FastAPI 서버에 GET 요청 보냄
    • 상태 코드: 200 OK → 요청 성공
    • 응답 헤더: 서버가 보낸 정보 (Content-Type, X-Process-Time 등)
    • 요청 헤더: 클라이언트(브라우저)가 보낸 정보 (Accept, Cookie, User-Agent 등)

    1. 일반 정보 (요청 정보)
    항목 의미
    요청 URL http://127.0.0.1:8000/ — 루트("/") 경로 요청
    요청 메서드 GET — 데이터 조회용 요청
    상태 코드 200 OK — 정상 응답
    원격 주소 127.0.0.1:8000 — 로컬 서버
    리퍼러 정책 strict-origin-when-cross-origin — 크로스 도메인 요청 시 리퍼러 제어 정책
    2. 응답 헤더
    설명
    Content-Length 32 응답 데이터 바이트 수
    Content-Type application/json 응답 데이터가 JSON 형식임
    Date Wed, 23 Jul 2025 19:19:08 GMT 응답한 시간 (UTC)
    Server uvicorn FastAPI 서버 백엔드가 uvicorn
    X-Process-Time 0.0003... 요청 처리에 걸린 시간 (초, 미들웨어에서 설정됨)
    3. 요청 헤더
    설명
    Accept text/html,... 브라우저가 수용 가능한 응답 타입들
    Accept-Encoding gzip, deflate, br, zstd 압축 방식
    Accept-Language ko-KR,... 수용 가능한 언어
    Cache-Control max-age=0 캐시 사용 안 함 (최신 요청 원함)
    Connection keep-alive 연결 유지
    Cookie 다양한 세션 정보 포함 <br>csrftoken, sessionid, _xsrf 등 → 대부분 로그인, 인증 관련 정보
    Host 127.0.0.1:8000 요청 보낸 서버 주소
    User-Agent Mozilla/5.0... 브라우저 정보 (Chrome, Windows)

    주요 포인트

    • FastAPI 서버 정상 작동 중 (200 OK, application/json, uvicorn)
    • X-Process-Time 헤더는 미들웨어가 응답 시간 측정에 성공했다는 의미
    • 요청 헤더에는 브라우저 기본 정보와 함께 cookie에 세션/CSRF 토큰이 자동 포함됨
    • 개발용 환경이기 때문에 127.0.0.1에서 테스트 중

    헤더는 서버와 클라이언트 간의 약속입니다. 헤더는 택배 상자의 운송장이라고 앞전에 언급했습니다.

    • 택배 상자 안에는 우리가 보내고 싶은 데이터(body) 가 들어 있고,
    • 바깥에는 운송장(header) 이 붙어 있어요.
      • 어디로 보내는지 (Host)
      • 누가 보냈는지 (Authorization)
      • 어떤 포장인지 (Content-Type)
      • 뭘로 받고 싶은지 (Accept)

    즉, 서버가 그 요청을 올바르게 이해하고 처리하려면,
    운송장(헤더)을 꼭 붙여야 하는 거예요!

    비유하자면 클라이언트(사용자)는 택배를 보내는 사람이고, 헤더는 운송장이며 미들웨어는 택배 창구 직원입니다.

    사용자가 택배를 보내면, 창구 직원(미들웨어)이 운송장(헤더)을 보고:

    • 주소가 잘 되었는지 확인하고
    • 무게를 재서 처리 시간(X-Process-Time)을 붙이고
    • 보안 검사도 하고
    • 스티커(응답 헤더)를 하나 더 붙여서 서버에 전달하는 것!

    우리가 연습한 코드는 FastAPI의 미들웨어 기능중 일부이며 응답 헤더에 처리 시간(X-Process-Time)을 기록하는 미들웨어를 테스트해본 것입니다.

    그외에도 이런것들을 사용할수 있어요:

    • 요청 전 검사 : IP 제한, 토큰 확인, 요청 헤더 검사 등
    • 요청 처리 시간 측정 : time.time()으로 경과 시간 계산
    • 응답 헤더 추가 : X-Process-Time, X-API-Version 등 삽입
    • 로그 출력 : 요청/응답 정보를 로그로 기록
    • 예외 처리 : 에러 응답 포맷 지정
    • CORS, GZip, 세션 : 기본 내장 미들웨어 (자동 등록 또는 설정 필요)

    헤더 정보에 추가할 수 있는 주요 항목:

    인증 관련

    • Authorization: 인증 토큰 (예: Bearer <token>, Basic ...)
    • Cookie: 세션 정보 포함
    • X-CSRFToken: CSRF 보안 토큰 (주로 POST/PUT 등에서)

    데이터 형식 관련

    • Content-Type: 요청 본문의 타입 (예: application/json, multipart/form-data)
    • Accept: 원하는 응답 타입 (예: application/json, text/html)

    보안 및 출처 확인

    • Origin: 요청이 발생한 출처 (CORS 정책에 사용)
    • Referer: 사용자가 방금 전에 있던 페이지 주소
    • X-Requested-With: Ajax 요청 여부 확인 (예: XMLHttpRequest)

    클라이언트 정보

    • User-Agent: 브라우저/앱 종류 및 버전
    • Host: 요청 대상 서버 호스트 (예: example.com)

    커스텀 헤더 (개발자 정의 가능)

    • X-API-Version: API 버전 명시
    • X-App-Name: 앱 이름 또는 클라이언트 종류 식별
    • 기타 X- 접두사로 시작하는 자유 정의 헤더 가능
    TOP
    preload preload